home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Power 1996 September
/
MACPOWER-1996-09.ISO.7z
/
MACPOWER-1996-09.ISO
/
第2特集:プラグイン大集合
/
PIC2 Save
/
pic2maclib.c
< prev
next >
Wrap
Text File
|
1995-01-16
|
26KB
|
1,178 lines
/*
* PIC2 ファイル操作部 by やなぎさわ
*
*/
#define Photoshop_PlugIn
#define _PIC2_
#include "pic2.h"
#include "p2PlugInUtilities.h"
/* ----- 変数の宣言 ----- */
static uchar saver[30+1]; /* セーバ名 */
static short depth; /* 色数ただしビットの深さで入れる */
static short x_aspect; /* Xの比率 */
static short y_aspect; /* Yの比率 */
static long x_max; /* Xの最大サイズ */
static long y_max; /* Yの最大サイズ */
static short n_palette = 0; /* パレット数 */
static short palette_bits = 0; /* パレットの有効ビット長 */
static uchar palette_data[256][3]; /* パレットバッファ */
typedef union {
uchar d_char[4];
long d_long;
short d_short;
LONG d_LONG;
SHORT d_SHORT;
} any_t;
/* ------ プログラム ----- */
/*
* 文字列を指定文字数だけコピーをする。もし元の文字列が短い場合は
* スペースでうめる。
*/
static void
strcpy2(
uchar *dst, /* コピー先 */
uchar *src, /* コピー元 */
long n_str /* 文字数 */
)
{
for ( ;;) {
uchar c = *src++;
if ( c == '¥0') break;
if ( --n_str < 0) break;
*dst++ = c;
}
while ( --n_str >= 0) *dst++ = ' ';
}
/*
* memsetの長さが16ビット超でもOK版
*/
void
l_memset(
void _HUGE_ *mem, /* セットされるメモリ */
uchar data, /* データ */
long n /* 長さ(byte) */
)
{
uchar *p = (uchar *)mem;
while( --n >= 0) *p++ = data;
}
/*
* メモリを確保する
*
*/
static void* mem_alloc(long size)
{
void* p;
p = (void*)NewPtrClear(size);
if (p == NULL)
{
p2errno = MemError();
return NULL;
}
// memset( p, 0, size);
return p;
}
#ifdef BIG_ENDIAN
# define conv_endian_short(x)
# define conv_endian_long(x)
#else
/*
* 'data'中のshortデータのバイトオーダーを入れ替える。
*/
static void
conv_endian_short(
any_t *data /* 入れ替え対象のデータ */
)
{
uchar c;
c = data->d_char[0];
data->d_char[0] = data->d_char[1];
data->d_char[1] = c;
}
/*
* 'data'中のlongデータのバイトオーダーを入れ替える
*/
static void
conv_endian_long(
any_t *data /* 入れ替え対象のデータ */
)
{
uchar c;
c = data->d_char[0];
data->d_char[0] = data->d_char[3];
data->d_char[3] = c;
c = data->d_char[1];
data->d_char[1] = data->d_char[2];
data->d_char[2] = c;
}
/*
* longデータをLONG(big endian)データに変換
*/
LONG /* big endianな long */
long2LONG(
long n /* 元のlong */
)
{
any_t d;
d.d_long = n;
conv_endian_long( &d);
return ( d.d_LONG);
}
/*
* shortデータをSHORT(big endian)データに変換
*/
SHORT /* big endianな short */
short2SHORT(
short n /* 元のshort */
)
{
any_t d;
d.d_short = n;
conv_endian_short( &d);
return ( d.d_SHORT);
}
/*
* LONG( big endian)をlongに変換
*/
long /* 変換後のlong */
LONG2long(
LONG n /* big endian な long */
)
{
any_t d;
d.d_LONG = n;
conv_endian_long( &d);
return ( d.d_long);
}
/*
* SHORT( big endian)をshortに変換
*/
short /* 変換後のshort */
SHORT2short(
SHORT n /* big endian な short */
)
{
any_t d;
d.d_SHORT = n;
conv_endian_short( &d);
return ( d.d_short);
}
#endif /* BIG_ENDIAN */
long read_file(P2* p2, void* mem, long size)
{
OSErr result;
long readsize = size;
result = FSRead(p2->fds, &readsize, (Ptr)mem);
if (result != noErr)
p2errno = p2->errno = result;
else if (readsize < size)
p2errno = p2->errno = P2E_FEOF;
return readsize;
}
/*
* ファイルから指定量のデータを読み込む、ただしEOFを超えても
* エラーがセットされないのが違うだけです。
*/
long read_file2(P2* p2, void* mem, long size)
{
OSErr result;
long readsize = size;
result = FSRead(p2->fds, &readsize, (Ptr)mem);
if (result != noErr && result != eofErr)
p2errno = p2->errno = result;
return readsize;
}
/*
* ファイルから1バイト読み込む
*/
uchar /* 読み込んだ値 */
read_char(
P2 *p2 /* ハンドル */
)
{
uchar a;
read_file( p2, &a, 1);
return( a);
}
/*
* ファイルから shortデータを読み込む
*/
ushort /* 読み込んだ値 */
read_short(
P2 *p2 /* ハンドル */
)
{
any_t data;
read_file( p2, &data, 2);
/* エンディアンの修正 */
conv_endian_short( &data);
return ( data.d_short);
}
#if 0
/*
* ファイルから longデータを読み込む
*/
ulong /* 読み込んだ値 */
read_long(
P2 *p2 /* ハンドル */
)
{
any_t data;
read_file( p2, &data, 4);
/* エンディアンの修正 */
conv_endian_long( &data);
return ( data.d_long);
}
#endif
/*
* ファイルに指定量のデータを書き込む
*/
long write_file(P2* p2, void* mem, long size)
{
OSErr result;
long writesize = size;
result = FSWrite(p2->fds, &writesize, (Ptr)mem);
if (result != noErr)
p2errno = p2->errno = result;
else if (writesize != size)
p2->errno = p2errno = dskFulErr;
return writesize;
}
/*
* ファイルに1バイト書き込む
*/
long /* 書き込んだ量 (1のはず ) */
write_char(
P2 *p2, /* ハンドル */
char a /* データ */
)
{
return ( write_file( p2, &a, 1));
}
/*
* ファイルに shortデータを書き込む
*/
long /* 書き込んだ量 ( 2のはず) */
write_short(
P2 *p2, /* ハンドル */
short n /* データ */
)
{
any_t data;
data.d_short = n;
/* エンディアン変換 */
conv_endian_short( &data);
return ( write_file( p2, &data.d_SHORT, 2));
}
/*
* ファイルにlongデータを書き込む
*/
long /* 書き込んだ量 ( 4のはず ) */
write_long(
P2 *p2, /* ハンドル */
long n /* データ */
)
{
any_t data;
data.d_long = n;
/* エンディアン変換 */
conv_endian_long( &data);
return ( write_file( p2, &data.d_LONG, 4));
}
/*
* ファイルをシークする
*/
long seek_file(P2* p2, long pos)
{
OSErr result;
long filesize;
pos += p2->macbin_offset;
// Change for Macintosh:
// シークだけでファイルサイズを大きくできないので SetEOF を使う。
GetEOF(p2->fds, &filesize);
if(p2->mode == P2_OPEN_WRITE && pos>filesize)
SetEOF(p2->fds, pos);
result = SetFPos(p2->fds, fsFromStart, pos);
if (result != noErr)
{ p2errno = p2->errno = result;
return -1;
}
pos -= p2->macbin_offset;
return pos;
}
/*
* ファイルの現在の位置を得る
*/
long tell_file(P2* p2)
{
OSErr result;
long n;
result = GetFPos(p2->fds, &n);
if (result != noErr)
{ p2errno = p2->errno = result;
return -1;
}
n -= p2->macbin_offset;
return n;
}
/*
* セーブするデータ用にパレットを設定する。
* (なお、既にオープンされているP2ファイルには設定できない)
*/
void
p2setpal(
short n_pal, /* パレット数 */
short n_bits, /* パレット有効ビット長 */
uchar pal[][3] /* パレットデータ */
)
{
// assert( 0 < n_pal && n_pal <= 256);
// assert( 0 < n_bits && n_bits <= 256);
/* パレット数を保存 */
n_palette = n_pal;
/* パレット有効ビット長を保存 */
palette_bits = n_bits;
memcpy( palette_data, pal, n_pal * 3);
}
/*
* フレームバッファ/セーバ/作者名などの環境をセットする
*/
void
p2setenv(
char *savername, /* セーバ名 */
short ncolor, /* 色数をビット数 */
long xmax, /* 最大幅(−1で自動) */
long ymax, /* 最大高(−1で自動 */
short xasp, /* 横比率 */
short yasp, /* 縦比率 */
short rawbeta /* ベタ展開形式(0=他と同じ/1=ベタのまま) */
)
{
strncpy( (char *)saver,(char *)savername, 30);
saver[30] = '¥0';
depth = ncolor;
x_max = xmax;
y_max = ymax;
x_aspect = xasp;
y_aspect = yasp;
raw_beta = rawbeta;
}
/*
* ヘッダを読み込む
*/
static void
read_header( P2 *p2)
{
#if 0
//#ifndef PADDING_STRUCT
read_file( p2, &p2->header, sizeof( p2->header));
#else
read_file( p2, p2->header.magic, 4);
read_file( p2, p2->header.name, 18);
read_file( p2, p2->header.subtitle, 8);
read_file( p2, p2->header.crlf0, 2);
read_file( p2, p2->header.title, 30);
read_file( p2, p2->header.crlf1, 2);
read_file( p2, p2->header.saver, 30);
read_file( p2, p2->header.crlf2, 2);
read_file( p2, &p2->header.eof, 1);
read_file( p2, &p2->header.reserve0, 1);
read_file( p2, &p2->header.flag, 2);
read_file( p2, &p2->header.no, 2);
read_file( p2, &p2->header.time, 4);
read_file( p2, &p2->header.size, 4);
read_file( p2, &p2->header.depth, 2);
read_file( p2, &p2->header.x_aspect, 2);
read_file( p2, &p2->header.y_aspect, 2);
read_file( p2, &p2->header.x_max, 2);
read_file( p2, &p2->header.y_max, 2);
read_file( p2, &p2->header.reserve1, 4);
#endif
}
/*
* ヘッダを書き込む
*/
static void
write_header( P2 *p2)
{
#if 0
//#ifndef PADDING_STRUCT
write_file( p2, &p2->header, sizeof( p2->header));
#else
write_file( p2, p2->header.magic, 4);
write_file( p2, p2->header.name, 18);
write_file( p2, p2->header.subtitle, 8);
write_file( p2, p2->header.crlf0, 2);
write_file( p2, p2->header.title, 30);
write_file( p2, p2->header.crlf1, 2);
write_file( p2, p2->header.saver, 30);
write_file( p2, p2->header.crlf2, 2);
write_file( p2, &p2->header.eof, 1);
write_file( p2, &p2->header.reserve0, 1);
write_file( p2, &p2->header.flag, 2);
write_file( p2, &p2->header.no, 2);
write_file( p2, &p2->header.time, 4);
write_file( p2, &p2->header.size, 4);
write_file( p2, &p2->header.depth, 2);
write_file( p2, &p2->header.x_aspect, 2);
write_file( p2, &p2->header.y_aspect, 2);
write_file( p2, &p2->header.x_max, 2);
write_file( p2, &p2->header.y_max, 2);
write_file( p2, &p2->header.reserve1, 4);
#endif
}
static void
read_blk_header_from_flag( P2 *p2)
{
#if 0
//#ifndef PADDING_STRUCT
read_file( p2, (char *)&p2->blk + offsetof( struct p2_blk, flag)
, sizeof( p2->blk) - offsetof( struct p2_blk, flag));
#else
/* read_file( p2, p2->blk.id, 4); */
/* read_file( p2, &p2->blk.size, 4); */
read_file( p2, &p2->blk.flag, 2);
read_file( p2, &p2->blk.x_wid, 2);
read_file( p2, &p2->blk.y_wid, 2);
read_file( p2, &p2->blk.x_offset, 2);
read_file( p2, &p2->blk.y_offset, 2);
read_file( p2, &p2->blk.opaque, 4);
read_file( p2, &p2->blk.reserve, 4);
#endif
}
static void
write_blk_header( P2 *p2)
{
#if 0
//#ifndef PADDING_STRUCT
write_file( p2, &p2->blk, sizeof( p2->blk));
#else
write_file( p2, &p2->blk.id, 4);
write_file( p2, &p2->blk.size, 4);
write_file( p2, &p2->blk.flag, 2);
write_file( p2, &p2->blk.x_wid, 2);
write_file( p2, &p2->blk.y_wid, 2);
write_file( p2, &p2->blk.x_offset, 2);
write_file( p2, &p2->blk.y_offset, 2);
write_file( p2, &p2->blk.opaque, 4);
write_file( p2, &p2->blk.reserve, 4);
#endif
}
/*
* pic2ファイルを読み込みでオープンする。
*/
P2* p2open(FSSpec* fname)
{
P2 * p2;
short fds = 0;
OSErr result;
long comment_size;
/* とりあえず ファイルをオープンする */
result = HOpen(fname->vRefNum, fname->parID, fname->name, fsCurPerm, &fds);
if (result != noErr)
{
p2errno = result;
return NULL;
}
/* 必要なメモリを確保してハンドルを作る。
* (なおメモリ確保関数内でのメモリクリアが暗示的な初期化になっている。)
*/
p2 = mem_alloc( sizeof( *p2));
if ( p2 == NULL) goto err;
p2->fds = fds;
p2->mode = P2_OPEN_READ;
/* pic2のヘッダを読み込む */
read_header( p2);
/* マックバイナリ簡易対応 */
if ( memcmp( p2->header.magic, "P2DT", 4) != 0) {
/* もしIDが無い時は、128バイト先にIDがあるか見てみる */
seek_file( p2, 128);
read_header( p2);
if ( memcmp( p2->header.magic, "P2DT", 4) != 0) {
p2errno = p2->errno = P2E_BADFORM;
goto err;
}
p2->macbin_offset = 128;
}
/* パレットがある場合はパレットも読む */
if ( SHORT2short( p2->header.flag) & 1) {
p2->pal_bits = read_char( p2);
p2->n_pal = read_short( p2);
read_file( p2, p2->pal, p2->n_pal * 3);
}
/* コメントの読み込み */
comment_size = LONG2long( p2->header.size) - tell_file( p2);
p2->comment = mem_alloc( comment_size + 1);
if ( p2->comment == NULL) goto err;
read_file( p2, p2->comment, comment_size);
/* サイズ取得 */
p2->x_max = SHORT2short( p2->header.x_max);
p2->y_max = SHORT2short( p2->header.y_max);
/* 始めのブロック位置セット */
p2->next_pos = tell_file( p2);
/* エラーが無かった時はハンドルを戻す */
if ( p2->errno == 0) return ( p2);
err:; /* エラー時は、確保したメモリを解放して NULLを戻す */
if ( p2 != NULL) {
FREE( p2->comment);
}
FREE( p2);
FSClose(fds);
return ( NULL);
}
/*
* pic2ファイルを作成モードでオープンする。
*/
P2 * /* 成功時はハンドル、エラー時は NULL */
p2creat(
FSSpec *fname, /* ファイル名 */
char *title, /* タイトル */
char *comment, /* コメント */
char *name, /* 作者名 */
short no /* 作品番号 */
)
{
P2 *p2;
short fds;
OSErr result;
/* ファイルを作成 */
HDelete(fname->vRefNum, fname->parID, fname->name);
result = HCreate(fname->vRefNum, fname->parID, fname->name, 'Q4ツd', 'PIC2');
if (result != noErr)
{
erropen:;
p2errno = result;
return (NULL);
}
result = HOpen(fname->vRefNum, fname->parID, fname->name, fsRdWrPerm, &fds);
if (result != noErr) goto erropen;
/* ハンドラの確保と初期化
* (なおメモリ確保でのメモリクリアが暗示的な初期化になっている。)
*/
p2 = mem_alloc( sizeof( *p2));
if ( p2 == NULL) goto err;
p2->fds = fds;
p2->mode = P2_OPEN_WRITE;
/* ヘッダは最後に書き込むので取り敢えずシークしとく
* (無い所シークできない人は代わりにダミーで何か書いてね)
*/
seek_file( p2, SIZE_OF_HEADER);
/* パレットを書き込むぞ */
if ( n_palette > 0) {
write_char( p2, palette_bits);
write_short( p2, n_palette);
write_file( p2, palette_data, n_palette * 3);
}
/* コメントのセーブ */
/*
* Mac/Unix/DOS(Human68k,MS-DOS)間の改行処理の違いをこの関数の中で
* 吸収してしまうように変更しました。( by N.Abe 1994/02/15 )
*
*/
#define COM_CR 0x0d
#define COM_LF 0x0a
#define COM_TERM 0x00
if ( comment != NULL ) {
register char *q = comment;
uchar c;
while( (c=*q++) != '¥0' ) {
switch( c ) {
case '¥0' :
break;
case COM_CR:
if ( *q == COM_LF ) {
break;
}
case COM_LF:
write_char( p2, COM_CR );
write_char( p2, COM_LF );
break;
default :
write_char( p2, c );
break;
}
}
}
write_char( p2, COM_TERM );
#undef COM_CR
#undef COM_LF
#undef COM_TERM
/* 次にセーブするブロック位置をせっと */
p2->next_pos = tell_file( p2);
/* ヘッダに情報セット */
p2->header.size = long2LONG( p2->next_pos);
memcpy( p2->header.magic, "P2DT", 4);
strcpy2( p2->header.name, (uchar *)name, 18);
/* サブタイトルをファイル名から作る */
{
char *p,*pp;
Str255 str;
BlockMove(fname->name,str,63);
p = (char*)(&str[1]);
/* ドライブとパスと拡張子を取り除く (漢字ファイル名だととちる事がある) */
#if 0
if ( (pp = strrchr( p, ':')) != NULL) p = pp + 1;
if ( (pp = strrchr( p, '/')) != NULL) p = pp + 1;
if ( (pp = strrchr( p, '¥¥')) != NULL) p = pp + 1;
#endif
pp = strchr( p, '.');
/* 元の文字列を一時的に書き換えるので余りよろしくない ^^; */
if ( pp != NULL) *pp = '¥0';
strcpy2( p2->header.subtitle, (uchar *)p, 8);
}
p2->header.crlf0[0] = p2->header.crlf1[0] = p2->header.crlf2[0] = 0x0d;
p2->header.crlf0[1] = p2->header.crlf1[1] = p2->header.crlf2[1] = 0x0a;
strcpy2( p2->header.title, (uchar *)title, 30);
strcpy2( p2->header.saver, saver, 30);
p2->header.eof = 0x1a;
p2->header.reserve0 = p2->header.reserve1 = 0;
if ( n_palette > 0) {
p2->header.flag = short2SHORT( 1);
} else {
p2->header.flag = short2SHORT( 0);
}
p2->header.no = short2SHORT( no);
p2->header.depth = short2SHORT( depth);
p2->header.x_aspect = short2SHORT( x_aspect);
p2->header.y_aspect = short2SHORT( y_aspect);
p2->header.x_max = short2SHORT( x_max);
p2->header.y_max = short2SHORT( y_max);
/* ハンドラに情報をセット */
p2->n_pal = n_palette;
p2->pal_bits = palette_bits;
memcpy( p2->pal, palette_data, n_palette * 3);
p2->n_pal = n_palette;
p2->pal_bits = palette_bits;
memcpy( p2->pal, palette_data, n_palette * 3); /* パレットはコピーで取っておく
* ( 必要無い気もするけど ^^;) */
/* エラーが無かったらハンドルを戻す */
if ( p2->errno == 0) return ( p2);
err: /* エラー時は確保したメモリの解放などをする */
FREE( p2);
return ( NULL);
}
/*
* pic2 ファイルを追加モードでオープンする。
*/
P2 * /* 成功時はハンドル、エラー時は NULL */
p2apend(
FSSpec *fname, /* ファイル名 */
char *title, /* タイトル */
char *comment, /* コメント */
char *name, /* 作者名 */
short no /* 作品番号 */
)
{
P2 *p2;
short n;
short fds; OSErr result;
/* 取り敢えずリードでオープン */
p2 = p2open( fname);
if ( p2 == NULL) {
/* 新規作成でオープンし直す */
return ( p2creat( fname, title, comment, name, no));
}
if ( SHORT2short( p2->header.depth) != depth) {
p2close( p2);
p2errno = P2E_BADFORM;
return ( NULL);
}
/* 追加なので最後のブロック次まで移動する */
n = p2find( p2); /* はじめのブロックを探して */
while ( n > 0) {
n = p2next( p2); /* なくなるまで探しつづける */
}
if ( n != 0) { /* エラ-だったら終わり */
p2close( p2);
return ( NULL);
}
/* ファイルを書き込み用に開きなおす */
result = HOpen(fname->vRefNum, fname->parID, fname->name, fsCurPerm, &fds);
if (result != noErr)
{
p2close(p2);
return NULL;
}
FSClose( p2->fds);
/* 新しい情報を有効にする、ただしコメント変更は
* かなり面倒なので古い方のままである。
* また、このためタイトルも同じままにして有る。
*/
strcpy2( p2->header.name, (uchar *)name, 18);
strcpy2( p2->header.saver, saver, 30);
p2->header.no = short2SHORT( no);
p2->header.x_aspect = short2SHORT( x_aspect);
p2->header.y_aspect = short2SHORT( y_aspect);
p2->header.x_max = short2SHORT( x_max);
p2->header.y_max = short2SHORT( y_max);
p2->mode = P2_OPEN_WRITE;
p2->fds = fds;
return ( p2);
}
/*
* 圧縮/展開ようのメモリを必要なら開放する。
*/
static void
p2buffree(
P2 *p2 /* ハンドル */
)
{
if ( p2->buff != NULL) return;
FREE( p2->vram_prev);
FREE( p2->vram_now);
FREE( p2->vram_next);
FREE( p2->flag_now);
FREE( p2->flag_next);
FREE( p2->flag2_now);
FREE( p2->flag2_next);
FREE( p2->flag2_next2);
#if defined(_DOS_)
if ( p2->cache ) HFREE( p2->cache );
#else
FREE( p2->cache);
#endif
FREE( p2->cache_pos);
FREE( p2->mulu_tab);
}
/*
* P2をクローズする
*/
short /* 0=OK/-1=error */
p2close(
P2 *p2 /* p2ハンドル */
)
{
short err; OSErr result;
/* 書き込みモードの場合 */
if ( p2->mode == P2_OPEN_WRITE) {
/* ブロックの終わりを書き込む */
seek_file( p2, p2->next_pos);
write_long( p2, 0); /* ブロック終わりのID */
write_long( p2, 0); /* オマケでサイズ0を入れる */
/* ブロックの最大サイズが未セットの場合はセットする。 */
if ( SHORT2short( p2->header.x_max) < 0) {
p2->header.x_max = short2SHORT( p2->x_max);
}
if ( SHORT2short( p2->header.y_max) < 0) {
p2->header.y_max = short2SHORT( p2->y_max);
}
/* 作成時刻をセット */
// convert from unix time()...1970/1/1
// MacOS GetDateTime Returns 1904/1/1 UNIX+0x7c262f10 = MacOS
{
// OSUtils.h
unsigned long tim;
GetDateTime(&tim);
p2->header.time = tim - 0x7c262f10L; // time( NULL));
}
/* ヘッダの書き込み */
seek_file( p2, 0);
write_header( p2);
}
/* ファイルを閉じる */
if ( (result = FSClose( p2->fds)) < 0) p2->errno = result;
/* メモリの開放 */
p2buffree( p2);
FREE( p2->comment);
err = p2->errno;
FREE( p2);
/* エラーならエラーリターン */
if ( err != 0) {
return ( -1);
}
return ( 0);
}
/*
* 次のブロックを探す
*/
short /* 1=みっけ/0=おわり/2=見つけたけど未知のブロックだ/else=エラー */
p2next(
P2 *p2 /* p2 ハンドル */
)
{
long i;
long (*ld_init)(P2*);
long (*sv_init)(P2*,pix**);
/* 書き込みモードは有効な処理ではないのでエラーで抜ける */
if ( p2->mode != P2_OPEN_READ ) return ( -1);
/* これから読むブロックに移動 */
seek_file( p2, p2->next_pos);
/* 取り敢えず頭の所だけ読み込む */
read_file( p2, &p2->blk, 8);
if ( p2->errno != 0) return ( -1);
/* ブロックの終わりだったら、終わりでリターン */
if ( p2->blk.id[0] == 0) return ( 0);
/* 今のブロック位置セット */
p2->blk_pos = p2->next_pos;
/* 次のブロック位置セット */
p2->next_pos += LONG2long( p2->blk.size);
/* 知っているブロックかな */
if(GetBlockTag(mem2long(p2->blk.id), &ld_init, &sv_init)==2)
return 2; /* 知らないフォーマットだよん */
/* ブロックヘッダの続き(flagから)よみこむ */
read_blk_header_from_flag( p2);
/* p2->x_maxの全ブロック最大幅をチェックして必要なら更新 */
if ( SHORT2short( p2->blk.x_offset) + SHORT2short( p2->blk.x_wid) > p2->x_max) {
p2->x_max = SHORT2short( p2->blk.x_offset) + SHORT2short( p2->blk.x_wid);
}
/* p2->y_maxの全ブロック最大高をチェックして必要なら更新 */
if ( SHORT2short( p2->blk.y_offset) + SHORT2short( p2->blk.y_wid) > p2->y_max) {
p2->y_max = SHORT2short( p2->blk.y_offset) + SHORT2short( p2->blk.y_wid);
}
/* エラーなら、エラーリターン */
if ( p2->errno != 0) return ( -1);
return ( 1);
}
/*
* 始めブロックを探す
*/
short /* 1=みっけ/0=おわり/2=見つけたけど未知のブロックだ/else=エラー */
p2find(
P2 *p2 /* ハンドル */
)
{
/* 読み込みモードでなければエラーで終わり */
if ( p2->mode != P2_OPEN_READ ) return ( -1);
/* はじめの位置をセットして p2nextを呼ぶ */
p2->next_pos = LONG2long( p2->header.size);
return ( p2next( p2));
}
/*
* p2用の各種メモリを確保する
*/
static short /* 0=OK / -1 = エラー */
p2bufalloc(
P2 *p2 /* ハンドル */
)
{
short wid;
wid = SHORT2short( p2->blk.x_wid);
p2errno = 0;
p2->vram_prev = mem_alloc((wid + 8) * sizeof( pix));
p2->vram_now = mem_alloc((wid + 8) * sizeof( pix));
p2->vram_next = mem_alloc((wid + 8) * sizeof (pix));
p2->flag_now = mem_alloc( wid + 8);
p2->flag_next = mem_alloc( wid + 8);
p2->flag2_now = mem_alloc( wid + 8);
p2->flag2_next = mem_alloc( wid + 8);
p2->flag2_next2 = mem_alloc( wid + 8);
#if defined(_DOS_)
p2->cache = (pix (_HUGE_ *)[N_COLOR_CACHE+1])HALLOC( 8*8*8,sizeof( *p2->cache) );
if ( p2->cache == NULL ) {
p2errno = errno;
p2->cache = NULL;
}
#else
p2->cache = mem_alloc( ((long)sizeof( *p2->cache) * 8 * 8 * 8) );
#endif
p2->cache_pos = mem_alloc( sizeof( *p2->cache_pos) * 8 * 8 * 8);
p2->mulu_tab = mem_alloc( sizeof( *p2->mulu_tab) * 16384);
if ( p2errno != 0) {
p2buffree( p2);
return ( -1);
}
return ( 0);
}
/*
* ブロックデータを展開する
*
* 始めにp2find/p2nextでブロックを探しておいて
* 展開したいブロックの所で p2loadで展開を開始する。
* ひとつのp2ハンドラでは同時には展開/圧縮できないので注意、
* 同じファイルで2つハンドルをオープンすれば
* 同じファイルの違うブロックを同時に展開出来る。
*/
short /* 0= OK / -1 エラー */
p2load(
P2 *p2 /* ハンドル */
)
{
long (*ld_init)(P2*);
long (*sv_init)(P2*,pix**);
if(GetBlockTag(mem2long(p2->blk.id), &ld_init, &sv_init)==2)
{
/* 未知のIDはエラーでリターン */
p2errno = p2->errno = P2E_BADFORM;
return ( -1);
}
/* 展開用のバッファを確保して */
p2bufalloc( p2);
/* 該当 IDの初期化ルーチンに後はまかす */
return ( *ld_init)( p2);
}
/*
* ブロックデータにセーブをする
*
* セーブを開始する。そして戻り値で指定された(今は0ね)
* ライン番号の情報を *line へセットして次に p2nline を呼び出します。
* そして同様にライン番号と行バッファのポインタが戻るので
* 再びデータをセットして p2nlineを呼ぶことを繰り返す。
* なお、p2nlineの戻り値が-2で終わりです。(-1はエラー)
* なお、0から最終ラインまで今の所連続してセットするように
* なっているので戻り値のライン番号情報を律義に考えなくても
* 特に問題はありません。
* ただし2パス圧縮の時は一回最終ラインまで行った後に再び0から
* 最終ラインを要求するので、この対応はしないといけません。
*
* ちなみに、始点がライン10でも0から要求されます。
* つまり座標値ではなくて始点からの番号です。
*/
long /* -1=エラー / else = 欲しいデータのライン番号 (0のはず)*/
p2save(
P2 *p2, /* ハンドル */
pix **line, /* データをセットして欲しいラインバッファが戻る */
long x, /* 始点 -1 でなし */
long y, /* 始点 -1 でなし */
long xw, /* 幅 */
long yw, /* 高さ */
char *id, /* ブロックID */
pix opaque /* 透明色 0xffffffffだとなし */
)
{
long (*ld_init)(P2*);
long (*sv_init)(P2*,pix**);
if(GetBlockTag(mem2long(id), &ld_init, &sv_init)==2)
{
/* 既知のIDではなければエラーでリターン */
p2errno = P2E_BADFORM;
return -1;
}
memcpy( p2->blk.id, id, 4);
p2->blk.x_wid = short2SHORT( xw);
p2->blk.y_wid = short2SHORT( yw);
p2->blk.x_offset = short2SHORT( x);
p2->blk.y_offset = short2SHORT( y);
p2->blk.reserve = short2SHORT( 0);
/* 最大幅情報を更新 */
if ( x < 0) x = 0;
if ( y < 0) y = 0;
if ( x + xw > p2->x_max) p2->x_max = x + xw;
if ( y + yw > p2->y_max) p2->y_max = y + yw;
/* 透明色をセット */
if ( opaque != 0xffffffff) {
p2->blk.flag = short2SHORT( 1);
p2->blk.opaque = long2LONG( opaque);
} else {
p2->blk.flag = short2SHORT( 0);
p2->blk.opaque = long2LONG( 0);
}
/* 圧縮に必要なバッファを確保 */
p2bufalloc( p2);
/* ブロックIDに応じた初期化ルーチンに後は任せる */
return (*sv_init)(p2, line);
}
/*
* ブロックデータに次のラインをセーブ/ロードをする
*
* セーブ時
* セーブ時はp2saveでもらったラインのデータをセットして呼び出します。
* そしてライン番号と行バッファのポインタが戻るので再びデータをセットして
* p2nlineを呼ぶことを繰り返します。
* なお、おわり(-2)の時に特別な処理は必要有りません。
* また終わったら再びp2saveで次のブロックをセーブすることが出来ます。
*
* ロード時
* 次のラインを展開します。
* ライン番号とラインバッファのポインタが戻るので、このラインに
* ラインバッファの内容を転送すればOKです。
*/
long /* -2=おわり/-1=エラー/else=欲しいデータのライン番号 */
p2nline(
P2 *p2, /* ハンドル */
pix **line /* データをセットするラインバッファが戻る */
)
{
long res = p2->nextline( p2, line);
if ( res == -1) { /* error */
p2buffree( p2);
} else if ( res == -2) {
if ( p2->mode == P2_OPEN_WRITE) { /* save ok end */
long new_pos = tell_file( p2);
seek_file( p2, p2->next_pos);
p2->blk.size = long2LONG( new_pos - p2->next_pos);
write_blk_header( p2);
p2->next_pos = new_pos;
}
p2buffree( p2);
}
return ( res);
}
#if 0
/*
* エラーの表示
*/
void
p2error( char *s)
{
Str255 s1;
strncpy((char*)(&s1[1]),s,254);
s1[250]=0;
s1[0] = strlen((char*)(&s1[1]));
DebugStr(s1);
}
#endif
/* eof */